1
Principles of Mobile App Security
- Minimize sensitive data collection and retention.
- Assume client devices can be compromised and avoid trusting client-only checks.
- Use defense in depth: encrypt data at rest, use TLS for transport, validate inputs server-side, and apply least privilege for permissions.
- Fail securely by showing minimal error details and avoiding leak of internal state.
2
Transport Security and APIs
- Require HTTPS with strong TLS configuration and HSTS on servers.
- Enforce certificate validation; prefer platform TLS stacks and avoid custom TLS implementations.
- Use short-lived access tokens and refresh tokens for sessions.
- Validate and sanitize all server inputs; do not rely on client validation for authorization or rate-limiting.
- Apply server-side rate limits, parameter validation, and strict CORS/origin rules where web access applies.
3
Authentication and Tokens
- Use OAuth2 or OpenID Connect when integrating third-party identity providers.
- Store tokens securely; treat refresh tokens as highly sensitive.
- Implement refresh token rotation and revoke tokens on suspicious activity.
- Prefer Authorization Code Flow with PKCE for mobile apps rather than implicit flows.
- Validate token audience, issuer, expiry, and scopes on each API call.
Token Best Practices
- Never hard-code secrets, client IDs, or private keys in the app binary.
- Limit token scope to minimum privileges required by the client.
- Implement silent re-authentication and clear UX when user session expires.
4
Local Storage Options and Trade-offs
- Key-value small secrets: use secure platform storage (iOS Keychain, Android EncryptedSharedPreferences / Keystore).
- Structured local caching: use encrypted database (SQLCipher for sqflite or encrypted_preferences) when storing sensitive user records.
- File storage: encrypt files before writing and restrict file permissions; avoid storing sensitive data in public external storage.
- Light ephemeral cache: use SharedPreferences for non-sensitive settings only.
Selection Guide
- Secrets and tokens → Keychain / EncryptedSharedPreferences.
- Offline data with sensitivity → Encrypted database or file encryption.
- Non-sensitive UI state → SharedPreferences or local JSON cache.
5
Encryption and Key Management
- Use platform-backed key stores so keys are hardware-protected when available.
- Derive keys using secure KDFs when needed; avoid shipping static symmetric keys.
- Rotate keys and provide migration paths for encrypted data when keys change.
- For end-to-end encryption, manage keys server-assisted or user-derived with secure passphrases; never store raw private keys unencrypted on device.
Encryption Checklist
- Use AES-GCM or ChaCha20-Poly1305 for authenticated encryption.
- Use proper IV/nonce handling and unique nonces per encryption operation.
- Store metadata (algorithm, version) with ciphertext to support future migrations.
6
Secure Coding Practices
- Validate all inputs and avoid unsafe parsing of JSON or binary.
- Avoid reflection or dynamic code execution that could increase attack surface.
- Sanitize strings before sending to native components or webviews.
- Minimize and review third-party dependencies; keep them up to date and audit for vulnerabilities.
- Use static analysis tools and linters that identify unsafe patterns and potential leaks.
Key Patterns
- Principle of least privilege for Android permissions; request runtime permissions contextually.
- Use ProGuard / R8 for release builds to obfuscate code and reduce straightforward reverse-engineering.
- Strip debug symbols and disable developer features in production builds.
7
Protecting Secrets and API Keys
- Never embed API keys or secrets directly in source code or resources.
- Use backend proxying for privileged operations so the app talks to your server, which holds secrets.
- If third-party API keys must be on-device, restrict them via server-side usage restrictions, domain/app signing constraints, and short-lived tokens where possible.
- Use environment-specific configuration and CI secrets management for build-time credentials.
8
Secure Handling of User Data and Privacy
- Collect only necessary user data and provide clear consent dialogs.
- Follow regional privacy regulations (GDPR, CCPA) for data subject rights like deletion and export.
- Provide in-app privacy settings and a mechanism to delete cached or uploaded user data.
- Use anonymization and minimal retention windows for analytics and logs.
9
Network and Backend Validation Patterns
- Use server-side input validation, authorization checks per endpoint, and data-level masking for logs.
- Implement per-user authorization checks and object-level ACLs on the server.
- Validate any client-supplied identifiers before using them in queries or filesystem access to avoid injection and traversal attacks.
10
Secure Updates and Integrity Checks
- Use platform app stores for signed distribution; require code signing and verify signatures where possible.
- Consider using binary attestation or safety APIs to detect tampered environments if your threat model requires it.
- For OTA content or config fetched from the network, sign payloads and verify signatures before applying.
11
Logging, Error Handling, and Monitoring
- Avoid logging sensitive data (passwords, tokens, PII).
- Centralize error reporting with filters that redact sensitive fields before sending.
- Implement anomaly detection and monitoring on the backend to detect unusual behavior or abuse.
- Provide incident response steps and a revoke mechanism for compromised credentials.
12
Platform-Specific Notes
- iOS: use Keychain with access control flags (biometric, device passcode). Configure App Transport Security (ATS) and associated domains for Universal Links.
- Android: use EncryptedSharedPreferences or Keystore for key material and avoid storing secrets in plain SharedPreferences. Use Network Security Config to pin certificates if appropriate.
- Both: prefer platform APIs for cryptography and secure storage over custom implementations.
13
Testing Security
- Threat model and risk assessment to prioritize protections.
- Run static application security testing (SAST), dependency vulnerability scans, and dynamic tests (DAST) against backend endpoints.
- Perform penetration testing for high-risk apps and consider bug bounty or third-party audits for production systems.
- Automated security checks in CI for dependency vulnerabilities and secret scanning.
14
Backup, Migration, and Data Lifecycle
- Encrypt backups containing sensitive data or avoid storing sensitive data in backups altogether.
- Provide migration scripts when changing data schemas or encryption approaches.
- Implement clear retention policies and deletion routines for user-requested data removal.
15
Practical Recommendations and Quick Setup
- Use a secure storage plugin (flutter_secure_storage) for tokens and small secrets.
- Use an encrypted DB package or platform-backed encryption for persisted user data.
- Implement Authorization Code with PKCE for authentication flows.
- Centralize networking in a service layer with retry, backoff, and error normalization.
- Regularly run dependency audits and pin package versions in CI.
16
Exercises
1. Token storage and refresh
Implement secure token storage using platform-backed secure storage. Simulate token expiry and implement refresh with PKCE flow placeholders.
2. Encrypted local cache
Build a small data cache using an encrypted SQLite wrapper or file-level AES-GCM encryption. Demonstrate read, write, and migration when key version changes.
3. Threat model and checklist
Produce a one-page threat model for your app listing assets, threats, mitigations, and residual risks. Use it to prioritize two security improvements to implement.